package edu.corn.job.core.engine;

import edu.corn.job.core.engine.mutex.MutexPool;
import edu.corn.job.core.processor.AbstractJobProcessor;
import edu.corn.job.core.processor.ScheduleJobProcessor;
import edu.corn.job.core.statemachine.JobStateUtil;

import java.util.HashMap;
import java.util.Optional;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;


/**
 * 定时任务job框架。用于运行被提交的定时job。
 */
public class ScheduleJobEngine extends JobEngine {

    private final HashMap<String, Long> countMap = new HashMap<>();

    /**
     * 线程池。
     */
    protected ScheduledExecutorService scheduledExecutor;

    public ScheduleJobEngine(MutexPool mutexPool, ScheduledExecutorService executorService) {
        super(mutexPool);
        this.scheduledExecutor = executorService;
    }


    @Override
    public ExecutorService getExecutorService() {
        return this.scheduledExecutor;
    }

    @Override
    void doSubmit(JobRunner jobRunner) {
        AbstractJobProcessor jobProcessor = jobRunner.getContext().getJobAdapter().getJobProcessor();
        if (jobProcessor instanceof ScheduleJobProcessor scheduleJob) {
            // 按照
            dispatch(scheduleJob, jobRunner);
        } else {
            // 立即提交
            JobStateUtil.submit(jobRunner.getContext());
        }
    }

    private void dispatch(ScheduleJobProcessor scheduleJob, JobRunner jobRunner) {
        // 间隔时间
        Optional<Long> interval = scheduleJob.getInterval();
        // 延迟时间
        Optional<Long> delay = scheduleJob.getDelay();
        // 次数
        Optional<Long> count = scheduleJob.getCount();
        // cron表达式
        Optional<String> cronExpression = scheduleJob.getCronExpression();

        if (interval.isPresent()) {
            // 间隔时间不为空
            submitRecurringJob(jobRunner, delay.orElse(0L), interval.get(), TimeUnit.SECONDS, count.orElse(Long.MAX_VALUE));
        } else if (cronExpression.isPresent()) {
            // 执行cron处理。忽略间隔时间，延迟时间。
            // TODO 暂时不实现。

        } else {
            throw new UnsupportedOperationException();
        }


    }

    /**
     * 提交定时任务，在秒级后执行。
     *
     * @param runner
     * @param delay
     * @param timeUnit
     */
    private void submitDelayScheduledJob(JobRunner runner, long delay, TimeUnit timeUnit) {
        scheduledExecutor.schedule(runner, delay, timeUnit);
    }

    /**
     * 提交一个周期性任务
     *
     * @param runner       job上下文
     * @param initialDelay 初始延迟时间
     * @param period       执行周期
     * @param timeUnit     时间单位
     */
    public void submitRecurringJob(JobRunner runner, long initialDelay, long period, TimeUnit timeUnit, Long count) {
        countMap.put(runner.getContext().getMasterId(), count);
        scheduledExecutor.scheduleAtFixedRate(() -> {
            if (check(runner)) {
                runner.run();
            }
        }, initialDelay, period, timeUnit);
    }

    private Boolean check(JobRunner runner) {
        String masterId = runner.getContext().getMasterId();
        if (countMap.containsKey(masterId) && countMap.get(masterId) > 0) {
            countMap.put(masterId, countMap.get(masterId) - 1);
        }
        return false;
    }

}
